
package editor;

import graphic.Color;
import graphic.Graphic;
import graphic.LoadingFrame;
import graphic.Pointer;
import graphic.TextureBase;
import input.ActionState;
import input.Input;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import objects.ActionEngine;
import objects.Base;
import objects.Estate;
import objects.Mill;
import objects.Mob;
import objects.Tower;
import objects.Triangle;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.Display;
import org.lwjgl.util.vector.Vector3f;
import org.newdawn.slick.opengl.Texture;

/**
 *  
 * @author Marcin & Bartek
 * 
 * @description Can contain enough information to show map
 */
public class WorldQ implements Serializable{
    transient private List<Triangle> list = new ArrayList<>(); //serialized
    private List<Triangle> llist = new LinkedList<>(); //serialized
    public  List<Vector3f> checkPoint = new ArrayList<>(); //serialized
    transient Texture tex[]=new Texture[2]; // serialized
    transient Color white = new Color(1,1,1,1);
    transient public Mill mill;
    transient public Estate estate;
    public float size,res;//
    public int tX=0,tY=0;//
    public Vector3f millC;//
    public float[] esC=new float[]{0,0,0,0};//
    transient int ID;
    
    public WorldQ(){}
    
    public void toFile(String f){
        try {
            FileOutputStream fos=new FileOutputStream(f);
            DataOutputStream out = new DataOutputStream(fos);
            out.writeFloat(size);
            out.writeFloat(res);
            
            out.writeInt(tX);
            out.writeInt(tY);
            
            out.writeFloat(millC.x);
            out.writeFloat(millC.y);
            out.writeFloat(millC.z);
            
            out.writeFloat(esC[0]);
            out.writeFloat(esC[1]);
            out.writeFloat(esC[2]);
            out.writeFloat(esC[3]);
            
            out.writeInt(checkPoint.size());
            
            for(Vector3f v:checkPoint){
                out.writeFloat(v.x);
                out.writeFloat(v.y);
                out.writeFloat(v.z);
            }
            out.writeInt(llist.size());
            
            for(Triangle t:llist){
                t.toFile(out);
            }
            out.close();
            fos.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(WorldQ.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(WorldQ.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    public void fromFile(String f){
        try {
            FileInputStream fos=new FileInputStream(f);
            DataInputStream out = new DataInputStream(fos);
            size=out.readFloat();
            res=out.readFloat();
            
            tX=out.readInt();
            tY=out.readInt();
            millC=new Vector3f();
            millC.x=out.readFloat();
            millC.y=out.readFloat();
            millC.z=out.readFloat();
            
            esC[0]=out.readFloat();
            esC[1]=out.readFloat();
            esC[2]=out.readFloat();
            esC[3]=out.readFloat();
            
            int cpsize=out.readInt();
            
            for(int i=0;i<cpsize;++i){
                Vector3f v = new Vector3f();
                v.x=out.readFloat();
                v.y=out.readFloat();
                v.z=out.readFloat();
                checkPoint.add(v);
            }
            int listsize=out.readInt();
            
            for(int i=0;i<listsize;++i){
                Triangle t = new Triangle();
                t.fromFile(out);
                llist.add(t);
            }
            out.close();
            fos.close();
        } catch (FileNotFoundException ex) {
            Logger.getLogger(WorldQ.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(WorldQ.class.getName()).log(Level.SEVERE, null, ex);
        }
        load();
    }
    
    public void prepareToSave(){
        for(Triangle t:list){
            llist.add(t);
        }
        millC = mill.coord;
        esC[0]=estate.sx;
        esC[1]=estate.sz;
        esC[2]=estate.ex;
        esC[3]=estate.ez;
    }
    public void load(){
        mill=new Mill(millC.x,millC.y,millC.z,0.2f);
        estate=new Estate(esC[0],esC[1],esC[2],esC[3],3.f);
        list=new ArrayList<>();
        
        for(Triangle t:llist){
            if(t.type!=0) t.at=1;
            list.add(t);
        }
        white = new Color(1,1,1,1);
        tex=new Texture[2];
        tex[0]=TextureBase.get("images/GrassGreenTexture0004.png");
        tex[1]=TextureBase.get("images/cobble.png");
        ID=Graphic.e.createList();
        Graphic.e.startList(ID);
        {
            Graphic.e.setColor(white);
            Graphic.e.bind(tex[0]);
            Graphic.e.startDrawT();
            int type=0;
       
            for(Triangle t:list){
                if(type!=t.type){
                    type=t.type;
                    Graphic.e.endDraw();
                    Graphic.e.bind(tex[type]);
                    Graphic.e.startDrawT();
                }
                Graphic.e.drawTNswT(t);  
            }
            Graphic.e.endDraw();
            Graphic.e.unbind();
        }
        Graphic.e.endList();
        
    }
    
    public void draw(float rot)
    {
        Graphic.e.rotY(rot);
        Graphic.e.drawList(ID);
        mill.draw();
        estate.draw();
        Graphic.e.rotY(-rot);
    }
     public void editorDraw(boolean isMill, int isEstate,float rot){
        Graphic.e.rotY(rot);
        int type=0;
        Graphic.e.setColor(white);
        Graphic.e.bind(tex[0]);
        Graphic.e.startDrawT();
        for(Triangle t:list){
            if(type!=t.type){
                type=t.type;
                Graphic.e.endDraw();
                Graphic.e.bind(tex[type]);
                Graphic.e.startDrawT();
            }
            Graphic.e.drawTNswT(t);  
        }
        Graphic.e.endDraw();
        Graphic.e.unbind();
        if(isMill) mill.draw();
        if(isEstate==3) estate.draw();
        Graphic.e.rotY(-rot);
    }
    
    public WorldQ(float size, float res){
        tex[0]=TextureBase.get("images/GrassGreenTexture0004.png");
        tex[1]=TextureBase.get("images/cobble.png");
        
        this.res=res;
        this.size=size;
        
        list.clear();
        
        tX=(int)(size/res);
        tY=(int)(size/res);
        float t[][][]=new float[tX+1][tY+1][3];
        
        for(float i=0;i<tX+1;i++){
            for(float j=0;j<tY+1;j++){
                
                t[(int)i][(int)j][0]=i*res;
                t[(int)i][(int)j][1]=0.f;
                t[(int)i][(int)j][2]=j*res;
            }
        }
        for(float i=0;i<tX;i++){
            for(float j=0;j<tY;j++){
                Triangle buf = new Triangle();
                buf.x[1]=t[(int)i][(int)j][0];
                buf.texx[1]=0f;
                buf.x[0]=t[(int)i+1][(int)j][0];
                buf.texx[0]=1f;
                buf.x[2]=t[(int)i][(int)j+1][0];
                buf.texx[2]=0f;
                buf.y[1]=t[(int)i][(int)j][1];
                buf.y[0]=t[(int)i+1][(int)j][1];
                buf.y[2]=t[(int)i][(int)j+1][1];
                buf.z[1]=t[(int)i][(int)j][2];
                buf.texz[1]=0f;
                buf.z[0]=t[(int)i+1][(int)j][2];
                buf.texz[0]=0f;
                buf.z[2]=t[(int)i][(int)j+1][2];
                buf.texz[2]=1f;
                buf.type=0;
                buf.calcNormal();
                buf.number=list.size();
                list.add(buf);
                
                Triangle buf2 = new Triangle();
                buf2.x[0]=t[(int)i+1][(int)j+1][0];
                buf2.texx[0]=1f;
                buf2.x[1]=t[(int)i+1][(int)j][0];
                buf2.texx[1]=1f;
                buf2.x[2]=t[(int)i][(int)j+1][0];
                buf2.texx[2]=0f;
                buf2.y[0]=t[(int)i+1][(int)j+1][1];
                buf2.y[1]=t[(int)i+1][(int)j][1];
                buf2.y[2]=t[(int)i][(int)j+1][1];
                buf2.z[0]=t[(int)i+1][(int)j+1][2];
                buf2.texz[0]=1f;
                buf2.z[1]=t[(int)i+1][(int)j][2];
                buf2.texz[1]=0f;
                buf2.z[2]=t[(int)i][(int)j+1][2];
                buf2.texz[2]=1f;
                buf2.type=0;
                buf2.calcNormal();
                buf2.number=list.size();
                list.add(buf2);
            }
        }
    }
     public boolean ledge(int nr){
        if(nr%2==1)nr--;
        if((nr+2)%(tY*2)==0) return true;
        return false;
    }
    public boolean redge(int nr){
        if(nr%2==1)nr--;
        if((nr)%(tY*2)==0) return true;
        return false;
    }
    
    public void setVert0(int nr,float x, float y, float z,int wc){
        if(nr<0||nr>=list.size()) return;
        if((wc&1) == 1)list.get(nr).x[0]=x;
        if((wc&2) == 2)list.get(nr).y[0]=y;
        if((wc&4) == 4)list.get(nr).z[0]=z;
    }
    public void setVert1(int nr,float x, float y, float z,int wc){
        if(nr<0||nr>=list.size()) return;
        if((wc&1) == 1) list.get(nr).x[1]=x;
        if((wc&2) == 2) list.get(nr).y[1]=y;
        if((wc&4) == 4) list.get(nr).z[1]=z;
    }
    public void setVert2(int nr,float x, float y, float z,int wc){
        if(nr<0||nr>=list.size()) return;
        if((wc&1) == 1) list.get(nr).x[2]=x;
        if((wc&2) == 2) list.get(nr).y[2]=y;
        if((wc&4) == 4) list.get(nr).z[2]=z;
    }
    public void setVert0wl(int nr,float x, float y, float z,int wc){
        if(ledge(nr)) return;
        if(nr<0||nr>=list.size()) return;
        if((wc&1) == 1)list.get(nr).x[0]=x;
        if((wc&2) == 2)list.get(nr).y[0]=y;
        if((wc&4) == 4)list.get(nr).z[0]=z;
    }
    public void setVert1wl(int nr,float x, float y, float z,int wc){
        if(ledge(nr)) return;
        if(nr<0||nr>=list.size()) return;
        if((wc&1) == 1) list.get(nr).x[1]=x;
        if((wc&2) == 2) list.get(nr).y[1]=y;
        if((wc&4) == 4) list.get(nr).z[1]=z;
    }
    public void setVert2wl(int nr,float x, float y, float z,int wc){
        if(ledge(nr)) return;
        if(nr<0||nr>=list.size()) return;
        if((wc&1) == 1) list.get(nr).x[2]=x;
        if((wc&2) == 2) list.get(nr).y[2]=y;
        if((wc&4) == 4) list.get(nr).z[2]=z;
    }
    public void setVert0wr(int nr,float x, float y, float z,int wc){
        if(redge(nr)) return;
        if(nr<0||nr>=list.size()) return;
        if((wc&1) == 1)list.get(nr).x[0]=x;
        if((wc&2) == 2)list.get(nr).y[0]=y;
        if((wc&4) == 4)list.get(nr).z[0]=z;
    }
    public void setVert1wr(int nr,float x, float y, float z,int wc){
        if(redge(nr)) return;
        if(nr<0||nr>=list.size()) return;
        if((wc&1) == 1) list.get(nr).x[1]=x;
        if((wc&2) == 2) list.get(nr).y[1]=y;
        if((wc&4) == 4) list.get(nr).z[1]=z;
    }
    public void setVert2wr(int nr,float x, float y, float z,int wc){
        if(redge(nr)) return;
        if(nr<0||nr>=list.size()) return;
        if((wc&1) == 1) list.get(nr).x[2]=x;
        if((wc&2) == 2) list.get(nr).y[2]=y;
        if((wc&4) == 4) list.get(nr).z[2]=z;
    }
    
    public void changeTriangleVert(int nr,int v,float x, float y, float z,int wc){
        int tY2=tY*2;
        if(nr%2==0){//dolny
            if(v==0){
                setVert0(nr,x,y,z,wc);
                setVert1(nr+1,x,y,z,wc);
                setVert0wl(nr-1,x,y,z,wc);
                setVert1(nr+tY2,x,y,z,wc);
                setVert2wl(nr+tY2-1,x,y,z,wc);
                setVert2wl(nr+tY2-2,x,y,z,wc);
            }else if(v==1){
                setVert1(nr,x,y,z,wc);
                setVert2wl(nr-1,x,y,z,wc);
                setVert2wl(nr-2,x,y,z,wc);
                setVert0(nr-tY2,x,y,z,wc);
                setVert0wl(nr-tY2-1,x,y,z,wc);
                setVert1(nr-tY2+1,x,y,z,wc);
            }else if(v==2){
                setVert2(nr,x,y,z,wc);
                setVert2(nr+1,x,y,z,wc);
                setVert1wr(nr+2,x,y,z,wc);
                setVert0(nr-tY2+1,x,y,z,wc);
                setVert0wr(nr-tY2+2,x,y,z,wc);
                setVert1wr(nr-tY2+3,x,y,z,wc);
            }
        }else{//górny
            if(v==0){
                setVert0(nr,x,y,z,wc);
                setVert0wr(nr+1,x,y,z,wc);
                setVert1wr(nr+2,x,y,z,wc);
                setVert2(nr+tY2,x,y,z,wc);
                setVert2(nr+tY2-1,x,y,z,wc);
                setVert1wr(nr+tY2+1,x,y,z,wc);
            }else if(v==1){
                setVert1(nr,x,y,z,wc);
                setVert0(nr-1,x,y,z,wc);
                setVert0wl(nr-2,x,y,z,wc);
                setVert1(nr+tY2-1,x,y,z,wc);
                setVert2wl(nr+tY2-2,x,y,z,wc);
                setVert2wl(nr+tY2-3,x,y,z,wc);
            }else if(v==2){
                setVert2(nr,x,y,z,wc);
                setVert1wr(nr+1,x,y,z,wc);
                setVert2(nr-1,x,y,z,wc);
                setVert0(nr-tY2,x,y,z,wc);
                setVert0wr(nr-tY2+1,x,y,z,wc);
                setVert1wr(nr-tY2+2,x,y,z,wc);
            }
        }
    }
    
    public Triangle getTriangle(float gx,float gy){
        if(gx<0||gy<0||gx>size||gy>size) return null;
        gx/=res;
        gy/=res;
        
        int c=(int)gx*tY+(int)gy;
        c*=2;
        if(1-(gx-(int)gx)<gy-(int)gy) ++c;
        if(c<0 || c>=list.size()) return null;
        return list.get(c);
    }
    
    public int getTriangleNr(float gx,float gy){
        gx+=size/2;
        gy+=size/2;
        if(gx<0||gy<0||gx>size||gy>size) return -1;
        
        gx/=res;
        gy/=res;
        
        int c=(int)gx*tY+(int)gy;
        c*=2;
        if(1-(gx-(int)gx)<gy-(int)gy) ++c;
        if(c<0 || c>=list.size()) return -1;
        return c;
    }
}
